using System;
using System.Collections.Generic;
using System.Windows.Forms;
using OhioState.AssetManaged;
using OhioState.Graphics.Proxy;
using OhioState.Math;


namespace OhioState.Controls
{
    //
    // UniformVariablesControl - This controls is made to give a flexible interface for
    //  modifying uniform variables.  The control begins bare and is build automatically
    //  to be customized to the specific set of uniform variables.  As the user modifies this
    //  control, the changes are automatically reflected back into the uniform variables.
    //  This control handles arrays by putting each item of the array on a separate line.
    //  Note that this control sometimes takes a while to build itself so be aware of that.
    //
    public partial class UniformVariablesControl : UserControl
    {
        //public delegate void UVVChangedEvent(Object Value);

        //
        // Uniform Variable Values Dictionary
        //
        private Dictionary<String, UniformVariableValues> uvvs;

        //
        // Dictionary for looking up pretty names for the various types
        //
        private Dictionary<UniformVariableInfo.UniformType, String> PrettyNames;

        public UniformVariablesControl()
        {
            InitializeComponent();
            uvvs = null;

            // Setup pretty names
            PrettyNames = new Dictionary<UniformVariableInfo.UniformType, String>();
            PrettyNames.Add(UniformVariableInfo.UniformType.BOOL, "Boolean");
            PrettyNames.Add(UniformVariableInfo.UniformType.BOOL_VEC2, "Boolean Vector2");
            PrettyNames.Add(UniformVariableInfo.UniformType.BOOL_VEC3, "Boolean Vector3");
            PrettyNames.Add(UniformVariableInfo.UniformType.BOOL_VEC4, "Boolean Vector4");
            PrettyNames.Add(UniformVariableInfo.UniformType.FLOAT, "Float");
            PrettyNames.Add(UniformVariableInfo.UniformType.FLOAT_MAT2, "Matrix 2x2");
            PrettyNames.Add(UniformVariableInfo.UniformType.FLOAT_MAT3, "Matrix 3x3");
            PrettyNames.Add(UniformVariableInfo.UniformType.FLOAT_MAT4, "Matrix 4x4");
            PrettyNames.Add(UniformVariableInfo.UniformType.FLOAT_VEC2, "Float Vector2");
            PrettyNames.Add(UniformVariableInfo.UniformType.FLOAT_VEC3, "Float Vector2");
            PrettyNames.Add(UniformVariableInfo.UniformType.FLOAT_VEC4, "Float Vector4");
            PrettyNames.Add(UniformVariableInfo.UniformType.INT, "Integer");
            PrettyNames.Add(UniformVariableInfo.UniformType.INT_VEC2, "Integer Vector2");
            PrettyNames.Add(UniformVariableInfo.UniformType.INT_VEC3, "Integer Vector3");
            PrettyNames.Add(UniformVariableInfo.UniformType.INT_VEC4, "Integer Vector4");
            PrettyNames.Add(UniformVariableInfo.UniformType.SAMPLER_1D, "Sampler 1D");
            PrettyNames.Add(UniformVariableInfo.UniformType.SAMPLER_1D_SHADOW, "Sampler 1D Shadow");
            PrettyNames.Add(UniformVariableInfo.UniformType.SAMPLER_2D, "Sampler 2D");
            PrettyNames.Add(UniformVariableInfo.UniformType.SAMPLER_2D_SHADOW, "Sampler 2D Shadow");
            PrettyNames.Add(UniformVariableInfo.UniformType.SAMPLER_3D, "Sampler 3D");
            PrettyNames.Add(UniformVariableInfo.UniformType.SAMPLER_CUBE, "Sampler Cube");
        }

        //
        // Initialize the control.  Set up the table with all the appropriate sub controls
        //  as well as the events to trigger updating the values.
        //
        public void Init(Dictionary<String, UniformVariableValues> uvValues)
        {
            uvvs = uvValues;

            // Suspend Layout
            this.tableLayoutPanel.SuspendLayout();
            this.SuspendLayout();

            this.tableLayoutPanel.RowCount = uvvs.Keys.Count;
            foreach (RowStyle rs in this.tableLayoutPanel.RowStyles)
            {
                rs.SizeType = SizeType.AutoSize;
            }
            int row = 0;
            foreach (KeyValuePair<String, UniformVariableValues> kvp in uvvs)
            {
                for (int i = 0; i < kvp.Value.Size; i++)
                {
                    // Name
                    System.Windows.Forms.Label label;
                    if (kvp.Value.Size == 1)
                    {
                        label = NewLabel(kvp.Key);
                    }
                    else
                    {
                        label = NewLabel(kvp.Key + "[" + i.ToString() + "]");
                    }
                    this.tableLayoutPanel.Controls.Add(label, 0, row);
                    // Type
                    label = NewLabel(PrettyNames[kvp.Value.Type]);
                    this.tableLayoutPanel.Controls.Add(label, 1, row);
                    // Field
                    System.Windows.Forms.Control newControl = null;
                    switch (kvp.Value.Type)
                    {
                        // Basic types
                        case UniformVariableInfo.UniformType.BOOL:
                            newControl = NewBooleanComboBox(kvp.Key, kvp.Value, i);
                            break;
                        case UniformVariableInfo.UniformType.FLOAT:
                            newControl = NewFloatUpDown(kvp.Key, kvp.Value, i);
                            break;
                        case UniformVariableInfo.UniformType.INT:
                            newControl = NewIntUpDown(kvp.Key, kvp.Value, i);
                            break;

                        //
                        // Vectors
                        //
                        // Bool Vectors
                        case UniformVariableInfo.UniformType.BOOL_VEC2:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Bool, 2, i);
                            break;
                        case UniformVariableInfo.UniformType.BOOL_VEC3:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Bool, 3, i);
                            break;
                        case UniformVariableInfo.UniformType.BOOL_VEC4:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Bool, 4, i);
                            break;
                        // Float Vectors
                        case UniformVariableInfo.UniformType.FLOAT_VEC2:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Float, 2, i);
                            break;
                        case UniformVariableInfo.UniformType.FLOAT_VEC3:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Float, 3, i);
                            break;
                        case UniformVariableInfo.UniformType.FLOAT_VEC4:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Float, 4, i);
                            break;
                        // Int Vectors
                        case UniformVariableInfo.UniformType.INT_VEC2:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Int, 2, i);
                            break;
                        case UniformVariableInfo.UniformType.INT_VEC3:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Int, 3, i);
                            break;
                        case UniformVariableInfo.UniformType.INT_VEC4:
                            newControl = NewVectorControl(kvp.Key, kvp.Value, VectorControl.VectorType.Int, 4, i);
                            break;

                        //
                        // Matrices
                        //
                        // Matrix 2x2
                        case UniformVariableInfo.UniformType.FLOAT_MAT2:
                            newControl = NewMatrixControl(kvp.Key, kvp.Value, 2, i);
                            break;
                        // Matrix 3x3
                        case UniformVariableInfo.UniformType.FLOAT_MAT3:
                            newControl = NewMatrixControl(kvp.Key, kvp.Value, 3, i);
                            break;
                        // Matrix 4x4
                        case UniformVariableInfo.UniformType.FLOAT_MAT4:
                            newControl = NewMatrixControl(kvp.Key, kvp.Value, 4, i);
                            break;

                        //
                        // Samplers
                        //
                        // Sampler1D
                        case UniformVariableInfo.UniformType.SAMPLER_1D:
                            newControl = NewSamplerComboBox(kvp.Key, kvp.Value, 1, i);
                            break;
                        // Sampler2D
                        case UniformVariableInfo.UniformType.SAMPLER_2D:
                            newControl = NewSamplerComboBox(kvp.Key, kvp.Value, 2, i);
                            break;
                        // Sampler3D
                        case UniformVariableInfo.UniformType.SAMPLER_3D:
                            newControl = NewSamplerComboBox(kvp.Key, kvp.Value, 3, i);
                            break;
                    }
                    //
                    // Add control to table
                    //
                    if (newControl != null)
                    {
                        this.tableLayoutPanel.Controls.Add(newControl, 2, row);
                    }

                    row++;
                }
            }

            // Resume layout
            this.tableLayoutPanel.ResumeLayout(false);
            this.tableLayoutPanel.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        //
        // Make a new Label
        //
        private System.Windows.Forms.Label NewLabel(String text)
        {
            System.Windows.Forms.Label label = new System.Windows.Forms.Label();
            label.AutoSize = true;
            label.Margin = new System.Windows.Forms.Padding(3);
            label.Name = "label" + text;
            label.Text = text;
            return label;
        }

        //
        // Boolean Combo Box
        //  Make a new boolean combo box, set value, and set up events to modify uniform variable values
        //  on control modify.
        //
        private System.Windows.Forms.ComboBox NewBooleanComboBox(String name, UniformVariableValues value, int index)
        {
            System.Windows.Forms.ComboBox comboBox = new System.Windows.Forms.ComboBox();
            comboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            comboBox.FormattingEnabled = true;
            comboBox.Items.AddRange(new object[] {
            "False",
            "True"});
            comboBox.Margin = new System.Windows.Forms.Padding(3);
            comboBox.Name = "comboBox" + name + index.ToString();
            comboBox.Size = new System.Drawing.Size(57, 21);

            // Set Value
            comboBox.SelectedIndex = System.Convert.ToInt32(value[index].Bool);

            // Set Tag and update event
            comboBox.Tag = value[index];
            comboBox.SelectedIndexChanged += new System.EventHandler(comboBox_SelectedIndexChanged);
            return comboBox;
        }
        private void comboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            System.Windows.Forms.ComboBox comboBox = (System.Windows.Forms.ComboBox)sender;
            UniformVariableValueContainer value = (UniformVariableValueContainer)comboBox.Tag;
            value.BeginManipulation();
            value.Bool = System.Convert.ToBoolean(comboBox.SelectedIndex);
            value.EndManipulation();
        }

        //
        // Float numericUpDown
        //  Make a new Float numericUpDown, set value, and set up events to modify uniform variable values
        //  on control modify.
        //
        private System.Windows.Forms.NumericUpDown NewFloatUpDown(String name, UniformVariableValues value, int index)
        {
            System.Windows.Forms.NumericUpDown numericUpDown = new System.Windows.Forms.NumericUpDown();
            numericUpDown.AutoSize = true;
            numericUpDown.DecimalPlaces = 5;
            numericUpDown.Increment = new decimal(0.01f);
            numericUpDown.Margin = new System.Windows.Forms.Padding(3);
            numericUpDown.Maximum = new decimal(1000000);
            numericUpDown.Minimum = new decimal(-1000000);
            numericUpDown.Name = "floatUpDown" + name + index.ToString();

            // Set Value
            //changed by Oleg
            //numericUpDown.Value = System.Convert.ToDecimal(value[index].Float);
            if (value[index].Float == null) value[index].Float = new SharedFloat(0);
            numericUpDown.Value = System.Convert.ToDecimal(value[index].Float.Float_Value);

            // Set Tag and update event
            numericUpDown.Tag = value[index];
            numericUpDown.ValueChanged += new System.EventHandler(floatUpDown_ValueChanged);
            return numericUpDown;
        }
        private void floatUpDown_ValueChanged(object sender, EventArgs e)
        {
            System.Windows.Forms.NumericUpDown numericUpDown = (System.Windows.Forms.NumericUpDown)sender;
            UniformVariableValueContainer value = (UniformVariableValueContainer)numericUpDown.Tag;
            value.BeginManipulation();
            //changed by Oleg
            //value.Float = Decimal.ToSingle(numericUpDown.Value);
            value.Float = new SharedFloat(Decimal.ToSingle(numericUpDown.Value));
            value.EndManipulation();
        }

        //
        // Int numericUpDown
        //  Make a new Int numericUpDown, set value, and set up events to modify uniform variable values
        //  on control modify.
        //
        private System.Windows.Forms.NumericUpDown NewIntUpDown(String name, UniformVariableValues value, int index)
        {
            System.Windows.Forms.NumericUpDown numericUpDown = new System.Windows.Forms.NumericUpDown();
            numericUpDown.AutoSize = true;
            numericUpDown.DecimalPlaces = 0;
            numericUpDown.Increment = new decimal(1);
            numericUpDown.Margin = new System.Windows.Forms.Padding(3);
            numericUpDown.Maximum = new decimal(1000000);
            numericUpDown.Minimum = new decimal(-1000000);
            //numericUpDown.Name = "floatUpDown" + name + index.ToString();
            numericUpDown.Name = "intUpDown" + name + index.ToString();

            // Set Value
            if (value[index].Int == null) value[index].Int = new SharedInt(0);
            //numericUpDown.Value = System.Convert.ToInt32(value[index].Int);//ToDecimal(value[index].Int);
            numericUpDown.Value = System.Convert.ToDecimal(value[index].Int.Int_Value);

            // Set Tag and update event
            numericUpDown.Tag = value[index];
            numericUpDown.ValueChanged += new System.EventHandler(intUpDown_ValueChanged);
            return numericUpDown;
        }
        private void intUpDown_ValueChanged(object sender, EventArgs e)
        {
            System.Windows.Forms.NumericUpDown numericUpDown = (System.Windows.Forms.NumericUpDown)sender;
            UniformVariableValueContainer value = (UniformVariableValueContainer)numericUpDown.Tag;
            value.BeginManipulation();
            //value.Int = Decimal.ToInt32(numericUpDown.Value);
            //value.Float = Decimal.ToSingle(numericUpDown.Value);
            value.Int = new SharedInt(Decimal.ToInt32(numericUpDown.Value));
            value.EndManipulation();
        }

        //
        // Vector Control
        //  Make a vector control, set value, and set up events to modify uniform variable values
        //  on control modify.
        //
        private VectorControl NewVectorControl(String name, UniformVariableValues value, VectorControl.VectorType type, int size, int index)
        {
            VectorControl vectorControl = new VectorControl();
            vectorControl.AutoSize = true;
            vectorControl.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            vectorControl.DecimalPlaces = 5;
            vectorControl.Increment = 0.01F;
            vectorControl.Margin = new System.Windows.Forms.Padding(3);
            vectorControl.Max = 1000000F;
            vectorControl.Name = "vectorControl" + type.ToString() + name + index.ToString();
            vectorControl.Type = type;
            vectorControl.VectorSize = size;

            // Set Value - check if it is null, if so create a new value
            if (value[index].Vec == null)
            {
                if (type == VectorControl.VectorType.Bool)
                {
                    if (size == 2)
                        value[index].Vec = new Vector2b();
                    else if (size == 3)
                        value[index].Vec = new Vector3b();
                    else if (size == 4)
                        value[index].Vec = new Vector4b();
                }
                else if (type == VectorControl.VectorType.Float)
                {
                    if (size == 2)
                        value[index].Vec = new Vector2();
                    else if (size == 3)
                        value[index].Vec = new Vector3();
                    else if (size == 4)
                        value[index].Vec = new Vector4();
                }
                else if (type == VectorControl.VectorType.Int)
                {
                    if (size == 2)
                        value[index].Vec = new Vector2i();
                    else if (size == 3)
                        value[index].Vec = new Vector3i();
                    else if (size == 4)
                        value[index].Vec = new Vector4i();
                }
            }
            vectorControl.Value = value[index].Vec;

            // Set Tag and update event
            vectorControl.Tag = value[index];
            vectorControl.ValueChanged += new System.EventHandler(vectorControl_ValueChanged);
            return vectorControl;
        }
        private void vectorControl_ValueChanged_thisThread(object sender, EventArgs e)
        {
            VectorControl vectorControl = (VectorControl)sender;
            UniformVariableValueContainer value = (UniformVariableValueContainer)vectorControl.Tag;
            value.BeginManipulation();
            value.Vec = vectorControl.Value;
            value.EndManipulation();
        }
        //
        // Force the event to get called on the proper thread.
        //
        private void vectorControl_ValueChanged(object sender, EventArgs e)
        {
            System.EventHandler newEvent = new System.EventHandler(vectorControl_ValueChanged_thisThread);
            object[] args = new object[2];
            args[0] = sender;
            args[1] = e;
            //
            // We need to make sure these methods are executed on the correct thread.
            //
            this.Invoke(newEvent, args);
        }

        //
        // Matrix Control
        //  Make a matrix control, set value, and set up events to modify uniform variable values
        //  on control modify.
        //
        private MatrixControl NewMatrixControl(String name, UniformVariableValues value, int size, int index)
        {
            MatrixControl matrixControl = new MatrixControl();
            matrixControl.AutoSize = true;
            matrixControl.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
            matrixControl.DecimalPlaces = 5;
            matrixControl.Increment = 0.01F;
            matrixControl.Margin = new System.Windows.Forms.Padding(3);
            matrixControl.MatrixSize = size;
            matrixControl.Max = 1000000F;
            matrixControl.Name = "matrixControl" + name + index.ToString();

            // Set Value - check if it is null, if so create a new value
            if (value[index].Mat == null)
            {
                if (size == 2)
                    value[index].Mat = new Matrix2();
                else if (size == 3)
                    value[index].Mat = new Matrix3();
                else if (size == 4)
                    value[index].Mat = new Matrix4();
            }
            matrixControl.Value = value[index].Mat;

            // Set Tag and update event
            matrixControl.Tag = value[index];
            matrixControl.ValueChanged += new System.EventHandler(matrixControl_ValueChanged);
            return matrixControl;
        }
        private void matrixControl_ValueChanged_thisThread(object sender, EventArgs e)
        {
            MatrixControl matrixControl = (MatrixControl)sender;
            UniformVariableValueContainer value = (UniformVariableValueContainer)matrixControl.Tag;
            value.BeginManipulation();
            value.Mat = matrixControl.Value;
            value.EndManipulation();
        }
        //
        // Force the event to get called on the proper thread.
        //
        private void matrixControl_ValueChanged(object sender, EventArgs e)
        {
            System.EventHandler newEvent = new System.EventHandler(matrixControl_ValueChanged_thisThread);
            object[] args = new object[2];
            args[0] = sender;
            args[1] = e;
            //
            // We need to make sure these methods are executed on the correct thread.
            //
            this.Invoke(newEvent, args);
        }

        //
        // Sampler Combo Box
        //  Make a new sampler combo box, set value, and set up events to modify uniform variable values
        //  on control modify.
        //
        private System.Windows.Forms.ComboBox NewSamplerComboBox(String name, UniformVariableValues value, int dimensions, int index)
        {
            System.Windows.Forms.ComboBox comboBox = new System.Windows.Forms.ComboBox();
            comboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            comboBox.FormattingEnabled = true;
            comboBox.Margin = new System.Windows.Forms.Padding(3);
            comboBox.Name = "samplerComboBox" + name + index.ToString();
            //comboBox.Size = new System.Drawing.Size(57, 21);

            // Populate
            List<IAssetManaged> textures = null;
            if (dimensions == 1)
            {
                textures = AssetManager.Instance.FindAll(typeof(Texture1D));
            }
            else if (dimensions == 2)
            {
                textures = AssetManager.Instance.FindAll(typeof(Texture2D));
            }
            else if (dimensions == 3)
            {
                textures = AssetManager.Instance.FindAll(typeof(Texture3D));
            }
            if (textures != null)
            {
                foreach (IAssetManaged tex in textures)
                {
                    comboBox.Items.Add(tex);
                }
                // Set Value
                comboBox.SelectedItem = value[index].Sampler;
            }

            // Set Tag and update event
            comboBox.Tag = value[index];
            comboBox.SelectedIndexChanged += new System.EventHandler(samplerComboBox_SelectedIndexChanged);
            return comboBox;
        }
        private void samplerComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            System.Windows.Forms.ComboBox comboBox = (System.Windows.Forms.ComboBox)sender;
            UniformVariableValueContainer value = (UniformVariableValueContainer)comboBox.Tag;
            value.BeginManipulation();
            value.Sampler = (TextureProxy)comboBox.SelectedItem;
            value.EndManipulation();
        }

    }
}
